Skip to content

Stabilize DeepCompile ZeRO-3 memory scheduling - #8169

Open
tohtana wants to merge 11 commits into
deepspeedai:masterfrom
tohtana:tohtana/deepcompile-zero3-memory-stability-scheduler-standalone
Open

Stabilize DeepCompile ZeRO-3 memory scheduling#8169
tohtana wants to merge 11 commits into
deepspeedai:masterfrom
tohtana:tohtana/deepcompile-zero3-memory-stability-scheduler-standalone

Conversation

@tohtana

@tohtana tohtana commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Depends on #8159.

DeepCompile's ZeRO-3 scheduler does not consistently account for memory pressure across gather/release ordering, prefetch, selective gathering, and native gather-buffer reuse. This can retain excess gathered storage or trigger a full-parameter gather while Dynamo evaluates guards.

This PR adds rank-consistent scheduler budgeting and diagnostics, coordinates prefetch and selective gathering with graph profiling, reuses native gather storage within a bounded pressure-aware lifecycle, and avoids guard-time full-parameter gathers while the DeepCompile eager fallback is active.

tohtana added 2 commits July 22, 2026 17:50
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
@tohtana tohtana changed the title Tohtana/deepcompile zero3 memory stability scheduler standalone Stabilize DeepCompile ZeRO-3 memory scheduling Jul 23, 2026
tohtana added 4 commits August 2, 2026 10:51
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
@tohtana
tohtana marked this pull request as ready for review August 3, 2026 17:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 55779855e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread deepspeed/utils/allocator_telemetry.py Outdated
Comment thread deepspeed/utils/allocator_telemetry.py Outdated
tohtana added 3 commits August 3, 2026 11:23
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Comment thread csrc/compile/init.cpp
m.def("register_graph_z3",
&dc::register_graph_z3,
"Register graph with a list of ds parameter ids");
m.def("set_z3_gather_buffer_pool_budget_for_test",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if these new items are just test purpose only?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, these three new APIs are for testing purpose only. We need them to set or inspect the internal state of the memory pool. It doesn't look great to have these as public APIs, but I didn't have an idea about other approaches.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious if it is possible to do integration test rather than unit test on this level? For example, instead of writing the scaffold to test GatherBufferPool, can do a test of functions that call the natural creation of this class, e.g. calling from Z3CustomOpExecutor?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is actually how the current tests are structured. They do not construct or call GatherBufferPool directly. register_graph_z3() creates Z3CustomOpExecutor with the shared pool, and the CUDA test runs the real allgather_param, wait_allgather, and release_param ops.
The _for_test APIs are limited to making the budget and allocator-pressure inputs deterministic and exposing accounting of internal values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, your last sentence explains my confusion. OK, maybe we can call it deterministic or pre determined size etc?

Comment thread deepspeed/compile/inductor.py
Comment thread deepspeed/compile/util.py Outdated
Comment thread csrc/compile/z3.cpp
if (!enabled_ || pressure_recovery_in_progress_) { return at::Tensor(); }

Entry* best = nullptr;
for (auto& entry : entries_) {

@pengdurice pengdurice Aug 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is entries_ ordered? if not, is the full loop expensive vs an max heap like solution?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entries_ is currently an unsorted std::vector as we don't simply choose the maximum one (best fit to capacity, LRU for eviction, search by storage identity, etc.)
However, I don't think the scan is significant overhead. I expect the pool to contain tens of entries rather than thousands because it is byte-bounded and the dominant gather buffers are relatively large. Given an 80GB GPU, the hard cap is 80 GiB / 32 = 2.5 GiB. If we the average buffer size is 64MB, we will have 80 entries. This should be negligible in the C++ code.

@pengdurice

Copy link
Copy Markdown
Contributor

general question, do we have experiments results showcasing the changes' benefits?

Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Comment thread csrc/compile/z3.cpp
pool = std::make_shared<GatherBufferPool>();
weak_gather_buffer_pool = pool;
if (gather_buffer_pool_test_budget) {
pool->setBudgetForTest(gather_buffer_pool_test_budget.value());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setBudgetForTest is only called when it is test purpose?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. gather_buffer_pool_test_budget is unset by default and is populated only by set_z3_gather_buffer_pool_budget_for_test().

Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
@tohtana

tohtana commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

general question, do we have experiments results showcasing the changes' benefits?

Yes. We have some measurements although I have not rerun the exact current head yet.

The experiment used

  • Qwen3-14B
  • One node with 8 H100s
  • Activation checkpointing enabled
  • Micro-batch 4
  • Sequence length 4096
  • 10 warmup and 20 measured iterations

The results are:

  • With the ZeRO-3-only pass, the measured PyTorch caching-allocator retry count fell from 18–19 retries per rank to zero on every rank. Average step time improved by 8.4%, and throughput improved by 9.2%.
  • With the full DeepCompile pass, the retry count fell from 20 per rank to 2–4 per rank. Average step time improved by 9.2%, and throughput improved by 10.1%.
    For a longer run, from 31-300 steps, no allocator retry happened.

@pengdurice

Copy link
Copy Markdown
Contributor

general question, do we have experiments results showcasing the changes' benefits?

Yes. We have some measurements although I have not rerun the exact current head yet.

The experiment used

  • Qwen3-14B
  • One node with 8 H100s
  • Activation checkpointing enabled
  • Micro-batch 4
  • Sequence length 4096
  • 10 warmup and 20 measured iterations

The results are:

  • With the ZeRO-3-only pass, the measured PyTorch caching-allocator retry count fell from 18–19 retries per rank to zero on every rank. Average step time improved by 8.4%, and throughput improved by 9.2%.
  • With the full DeepCompile pass, the retry count fell from 20 per rank to 2–4 per rank. Average step time improved by 9.2%, and throughput improved by 10.1%.
    For a longer run, from 31-300 steps, no allocator retry happened.

That's great, maybe add that to the PR's description?

@pengdurice

Copy link
Copy Markdown
Contributor

the gather buffer pool and the memory budget seem to be two separate optimization, worth considering splitting to to PRs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants